
luachip.codex = {} //Get it? COde-inDEX!? ROFL
luachip.plent = {}

luachip.procent = nil
luachip.procpl = nil

luachip.recvTransmission = function(pl,rawcode)
	if luachipgc_CheckKillCode() then
		return
	end
	if IsEntity(pl) then
		local ent = luachip.plent[pl]
		if ent and IsEntity(ent) and not ent:IsWorld() and luachip.playerAccess(pl,ent) then
			luachip.codexAdd(pl,ent,rawcode)
		end
	end
end

lcTrans.setCommandFunction("luachipswep",luachip.recvTransmission)

luachip.codexAdd = function(pl,ent,rawcode)
	if luachipgc_CheckKillCode() then
		return
	end
	local code = luachip.parseCode(rawcode)
	
	luachip.procent = ent
	luachip.procpl = pl:UniqueID()
	
	local oldluachipEnts = ent.luachipEnts
	ent.luachipEnts = nil
	
	//Associate code with entity and execute
	
	ent:GetTable().luachipCode = rawcode
	ent:GetTable().luachipPlayer = pl
	local b,e = pcall(RunString,code)
	if not b then
		ErrorNoHalt("LUACHIP "..tostring(pl)..": "..tostring(e).."\n")
	end
	
	//Enable prop_physics PlayerUse
	if ent:GetClass() == "prop_physics" then
		if not ent:HasSpawnFlags(256) then
			local flags = tonumber(ent:GetKeyValues().spawnflags) or 0 //Returns a number, ensure it regardless
			ent:SetKeyValue("spawnflags",flags+256)
		end
	end
	
	//Proceed to linking stage
	if ent.luachipEnts and table.Count(ent.luachipEnts) > 0 then
		//See what links we can keep from the previous script
		
		if oldluachipEnts then
			for id,tab in pairs(oldluachipEnts) do
				if ent.luachipEnts[id] then
					ent.luachipEnts[id] = tab
				end
			end
		end
		oldluachipEnts = nil
		
		//Links restored
		
		luachip.xmitLinkedEnts(pl,ent)
	else
		//No links available
	end
	
	luachip.procent = nil
	luachip.procpl = nil
	
end

luachip.xmitLinkedEnts = function(pl,ent)
	if ent and IsEntity(ent) and ent:IsValid() and ent.luachipEnts and table.Count(ent.luachipEnts) > 0 then
		umsg.Start("lclink",pl)
			umsg.Entity(ent)
			umsg.Short(table.Count(ent.luachipEnts))
			local i = 0
			for k,v in pairs(ent.luachipEnts) do
				umsg.String(k)
				umsg.Entity(v.ent)
				umsg.String(v.description)
			end
			
			PrintTable(ent.luachipEnts)
		umsg.End()
	end
end

luachip.hooks = {}
luachip.metaHook = function(event_name,f)
	if luachip.procent then
		//You can only use the metahook and at script initialization
		local ent = luachip.procent
		
		//Establish metahook
		if not luachip.hooks[event_name] then
			luachip.hooks[event_name] = {}
		end
		luachip.hooks[event_name][ent] = f
	end
end

luachip.metaHookRemove = function(ent,event_name)
	if luachip.hooks[event_name] then
		luachip.hooks[event_name][ent] = nil
	end
end

//Meta functions

luachip._metaMsgBuffSZ = 251

//End meta functions

//KillCode alarm
kc_done = false
local kc_alarm = function()
	if kc_done then
		return
	end
	kc_done = true
	
	ErrorNoHalt("==================================================\n")
	ErrorNoHalt("==================================================\n")
	ErrorNoHalt("==========LUACHIP LOCKDOWN IS IN EFFECT!==========\n")
	ErrorNoHalt("==================================================\n")
	ErrorNoHalt("==================================================\n")
	ErrorNoHalt("KILL CODE TRIGGERED!\n")
	ErrorNoHalt("No more scripts will be executed!\n")
	ErrorNoHalt("Currently running hooks will be terminated!\n")
	ErrorNoHalt("To override, lua_run luachipgc_killcode = 0!\n")
	ErrorNoHalt("It is HIGHLY recommended that you update LuaChip as soon as possible!\n")
	ErrorNoHalt("All versions BELOW v"..tostring(luachipgc_killcode).." are affected!\n")
	ErrorNoHalt("There is no need to alert the internet as the fix is already available.\n")
	ErrorNoHalt("==================================================\n")
	ErrorNoHalt("==================================================\n")
	ErrorNoHalt("==========LUACHIP LOCKDOWN IS IN EFFECT!==========\n")
	ErrorNoHalt("==================================================\n")
	ErrorNoHalt("==================================================\n")
end
//

luachip.nextConsoleUpdateRate = 3
luachip.nextConsoleUpdate = CurTime()
luachip.codexThink = function()
	if luachipgc_CheckKillCode() then
		kc_alarm()
		return
	end
	
	//Call entity hooks
	for k,v in pairs{
		Think = true,
		ConsoleUpdate = luachip.nextConsoleUpdate < CurTime(),
	} do
		if v and luachip.hooks[k] then
			for ent,f in pairs(luachip.hooks[k]) do
				if not (ent and IsEntity(ent) and ent:IsValid() and f) then
					luachip.hooks[k][ent] = nil
				else
					local b,e = pcall(f)
					
					if not b then
						ErrorNoHalt(tostring(f)..": "..tostring(e).."\nThe hook will be removed.")
						luachip.hooks.Think[ent] = nil
					end
				end
			end
		end
	end
	
	//Update console
	if luachip.nextConsoleUpdate < CurTime() then
		for pl,ent in pairs(luachip.plent) do
			if pl and IsEntity(pl) and pl:IsPlayer() and ent and IsEntity(ent) and ent:IsValid() then
				umsg.Start("lcc",pl)
					umsg.String(ent:GetTable().luachipConsoleBuffer or "[Console output not available]")
				umsg.End()
			end
		end
		luachip.nextConsoleUpdate = CurTime() + 1/luachip.nextConsoleUpdateRate
	end
end

hook.Add("Think","luachip.codexThink",luachip.codexThink)

luachip.codexPlayerUse = function(pl,ent)
	if luachipgc_CheckKillCode() then
		kc_alarm()
		return
	end
	
	//Call entity hooks
	local k,v = "PlayerUse",true
	do
		if v and luachip.hooks[k] then
			//for ent,f in pairs(luachip.hooks[k]) do
			local f = luachip.hooks[k][ent]
			do
				if not (ent and IsEntity(ent) and ent:IsValid() and f) then
					luachip.hooks[k][ent] = nil
				else
					local b,e = pcall(f,pl:UniqueID())
					
					if not b then
						ErrorNoHalt(tostring(f)..": "..tostring(e).."\nThe hook will be removed.")
						luachip.hooks.Think[ent] = nil
					end
				end
			end
		end
	end
end

hook.Add("PlayerUse","luachip.codexPlayerUse",luachip.codexPlayerUse)

//Linking
luachip.ccLink = function(pl,cmd,args)
	if luachipgc_CheckKillCode() then
		return
	end
	local id = tostring(args[1])
	local lcent = tonumber(args[2])
	local ent = tonumber(args[3])
	if id == "" or id == "nil" or not lcent or not ent then
		return
	end
	
	lcent = ents.GetByIndex(lcent)
	if not (lcent and IsEntity(lcent) and lcent:IsValid()) then
		return
	end
	
	if not (lcent.luachipEnts and lcent.luachipEnts[id]) then
		return
	end
	
	ent = ents.GetByIndex(ent)
	if not (ent and IsEntity(ent) and ent:IsValid()) then
		return
	end
	
	if ent:IsWorld() then
		lcent.luachipEnts[id].ent = nil
		luachip.xmitLinkedEnts(pl,lcent)
	end
	
	if not (luachip.playerAccess(pl,lcent) and luachip.playerAccess(pl,ent)) then
		return
	end
	
	lcent.luachipEnts[id].ent = ent
	luachip.xmitLinkedEnts(pl,lcent)
end

concommand.Add("lclink",luachip.ccLink)


